//
// Created by wuxiangan on 2022/4/18.
//

#include "ThreadLocalStorage.h"

ThreadLocal::ThreadLocal(std::string name) {
    m_tid = std::this_thread::get_id();
    m_name = name;
}

ThreadLocal::~ThreadLocal() {
    s_thread_local_map_mutex.lock();
    s_thread_local_map.erase(GetTid());
    s_thread_local_map_mutex.unlock();
}

void ThreadLocal::PushMessage(ThreadMessage* msg) {
    m_message_queue_mutex.lock();
    m_message_queue.push(msg);
    m_message_queue_mutex.unlock();
}

ThreadMessage* ThreadLocal::PopMessage() {
    ThreadMessage* msg = NULL;
    m_message_queue_mutex.lock();
    if (!m_message_queue.empty()) {
        msg = m_message_queue.front();
        m_message_queue.pop();
    }
    m_message_queue_mutex.unlock();
    return msg;
}

std::vector<ThreadMessage*> ThreadLocal::PopAllMessage() {
    m_message_queue_mutex.lock();
    uint32_t size = m_message_queue.size();
    std::vector<ThreadMessage*> vec;
    for (int i = 0; i < size; i++) {
        vec.push_back(m_message_queue.front());
        m_message_queue.pop();
    }
    m_message_queue_mutex.unlock();
    return vec;
}

std::mutex ThreadLocal::s_thread_local_map_mutex;
std::unordered_map<std_thread_id, ThreadLocal*> ThreadLocal::s_thread_local_map;

ThreadLocal* ThreadLocal::GetThreadLocal() {
    std_thread_id tid = std::this_thread::get_id();
    s_thread_local_map_mutex.lock();
    s_thread_local_map.find(tid);
    std::unordered_map<std_thread_id, ThreadLocal*>::iterator it = s_thread_local_map.find(tid);

    ThreadLocal* tl = NULL;
    if (it == s_thread_local_map.end()) {
        tl = new ThreadLocal();
        s_thread_local_map[tid] = tl;
    } else {
        tl = it->second;
    }
    s_thread_local_map_mutex.unlock();
    return tl;
}

ThreadLocal* ThreadLocal::GetThreadLocalByName(std::string name) {
    ThreadLocal* tl = NULL;
    s_thread_local_map_mutex.lock();
    for (std::unordered_map<std_thread_id, ThreadLocal*>::iterator it = s_thread_local_map.begin(); it != s_thread_local_map.end(); it++)
    {
        ThreadLocal* tmp = it->second;
        if (tmp->GetName() == name) {
            tl = tmp;
            break;
        };
    }
    s_thread_local_map_mutex.unlock();
    return tl;
}

ThreadLocal* ThreadLocal::GetThreadLocalById(std_thread_id tid) {
    s_thread_local_map_mutex.lock();
    ThreadLocal* tl = s_thread_local_map.at(tid);
    s_thread_local_map_mutex.unlock();
    return tl;
}